package com.gitee.wsl.ext.string

import com.gitee.wsl.security.hash.md5
import com.gitee.wsl.text.regex.sample.isChinese

/**
 * @return [this] string with all non-alphanumeric characters,
 *         except for `-`, `_`, `@`, and `.`, replaced with [replacement]
 * @param replacement character to replace invalid characters with
 */
fun String.sanitizeFileName(replacement: String) = this.replace("[^a-zA-Z0-9\\-_.@]+".toRegex(), replacement)


fun String.validateFileName(maxFilenameLength: Int = 255): String {
    if (isEmpty()) {
        return ""
    }

    // 获取文件名和后缀名
    var name: String = this
    var extension = ""
    val dotIndex = lastIndexOf(".")
    if (dotIndex != -1) {
        name = substring(0, dotIndex)
        extension = substring(dotIndex)
    }

    // 检查文件名长度
    if (length > maxFilenameLength) {
        // 如果文件名过长，则截断后半部分
        name = name.take(maxFilenameLength - extension.length)
    }

    // 去除文件名中的非法字符
    name = name.replace("[\\\\/:*?\"<>|]".toRegex(), "")

    // 返回合法的文件名和后缀名
    return name + extension
}


val INVALID_FILE_NAME_CHARS = charArrayOf('/', '\\', ':', '*', '?', '"', '<', '>', '|', 0.toChar())

val INVALID_FILE_NAME_CHARS_STR = INVALID_FILE_NAME_CHARS.joinToString("")

val INVALID_FILE_NAME_REPLS = arrayOf<String>("_", "_", "_", "_", "_", "_", "_", "_", "_", "_")


fun isValidFileName(path: String): Boolean {
    if (path.isEmpty()) return false
    if (_containsControlAscii(path)) return false
    return !containsAnyChar(path, INVALID_FILE_NAME_CHARS_STR)
}


fun fileNameNoExt(path: String): String {
    val name = fileFullName(path)
    if ( name.length == 0) return name
    val pos = name.lastIndexOf('.')
    if (pos < 0) return name
    return name.take(pos)
}

/**
 * 与fileExt的区别在于，它在fileName中查找最后两个dot, 而不是最后一个dot。 例如 a.orm.xml对应fileType=orm.xml, 而fileExt=xml
 */

fun fileType(path: String): String {
    //if (path == null) return null
    var pos = path.lastIndexOf('/')
    if (pos < 0) pos = 0
    val pos2 = path.lastIndexOf('.')
    if (pos2 < pos) return ""
    if (pos2 == 0) return path.substring(pos2 + 1)

    val pos3 = path.lastIndexOf('.', pos2 - 1)
    if (pos3 < pos) return path.substring(pos2 + 1)
    return path.substring(pos3 + 1)
}


fun isValidFileType(name: String): Boolean {
    if (name.isEmpty()) return false

    if (!isValidFileName(name)) return false

    if (countChar(name, '.') > 2) return false

    return true
}


fun removeFileType(path: String?): String? {
    if (path == null) return null

    val fileType = fileType(path)
    if (fileType.isEmpty()) return path
    return path.take(path.length - fileType.length - 1)
}


fun replaceFileType(path: String?, fileType: String?): String? {
    if (path == null || fileType == null) return path
    return removeFileType(path) + (if (fileType.startsWith(".")) "" else ".") + fileType
}


fun fileExt(path: String): String {
    //if (path == null) return null
    val pos2 = path.lastIndexOf('.')
    if (pos2 < 0) return ""
    val pos = path.lastIndexOf('/')
    if (pos < 0 || pos2 > pos) return path.substring(pos2 + 1)
    return ""
}


fun fileExtFromFileType(fileType: String): String {
    return lastPart(fileType, '.')!!
}


fun removeFileExt(path: String?): String? {
    if (path == null) return null

    val fileExt = fileExt(path)
    if (!fileExt.isEmpty()) return path.substring(0, path.length - fileExt.length - 1)
    return path
}


fun replaceFileExt(path: String?, fileExt: String?): String? {
    if (path == null || fileExt == null) return path
    return removeFileExt(path) + (if (fileExt.startsWith(".")) "" else ".") + fileExt
}


fun fileFullName(path: String): String {
    return lastPart(path, '/', false)!!
}


fun fileName(path: String): String {
    return fileFullName(path)
}


fun filePath(path: String?): String? {
    if (path == null) return null
    val pos = path.lastIndexOf('/')
    if (pos < 0) return ""
    return path.substring(0, pos)
}


fun firstPart(str: String?, c: Char): String? {
    if (str == null) return null
    val pos = str.indexOf(c)
    if (pos < 0) return str
    return str.substring(0, pos)
}


fun lastPart(str: String?, c: Char, emptyIfNoSep: Boolean): String? {
    if (str == null) return null
    val pos = str.lastIndexOf(c)
    if (pos < 0) {
        return if (emptyIfNoSep) "" else str
    }
    return str.substring(pos + 1)
}


fun removeLastPart(str: String?, c: Char): String? {
    if (str == null) return null
    val pos = str.lastIndexOf(c)
    if (pos < 0) return ""
    return str.substring(0, pos)
}


fun lastPart(str: String?, c: Char): String? {
    return lastPart(str, c, false)
}


fun nextPart(str: String?, c: Char): String? {
    if (str == null) return null
    val pos = str.indexOf(c)
    if (pos < 0) return ""
    return str.substring(pos + 1)
}

fun filePathMd5(filePath: String): String {
    var fileName: String = fileFullName(filePath)
    // fileName仅仅用于显示。为了避免过长，这里限制了最大长度。唯一性靠md5保证
    if (fileName.length > 20) fileName = fileName.take(20)
    return filePath.md5() + '-' + fileName
}